// lunarCalendar.js
/**
 * 农历1900-2100的闰大小信息表
 * 0x代表十六进制，后面的是十六进制数
 * 每个十六进制数转换为二进制有12位，代表12个月
 * 二进制位为1表示该月为大月（30天），为0表示小月（29天）
 * 前12位代表闰月的情况，为0表示该年没有闰月
 */
const lunarInfo = [
  0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
  0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
  0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
  0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
  0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
  0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
  0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
  0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, // 1970-1979
  0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
  0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
  0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
  0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
  0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
  0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
  0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
  0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
  0x092e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
  0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
  0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
  0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
  0x0d520  // 2100
]

// 天干地支
const Gan = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
const Zhi = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
const Animals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']

// 农历月份
const lunarMonths = ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊']
// 农历日
const lunarDays = [
  '初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十',
  '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
  '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十'
]

/**
 * 将阳历日期转换为农历日期
 * @param {number} yy 阳历年份
 * @param {number} mm 阳历月份 (1-12)
 * @param {number} dd 阳历日
 * @returns {object} 农历日期对象
 */
function solarToLunar(yy, mm, dd) {
  const baseDate = new Date(1900, 0, 31)
  const objDate = new Date(yy, mm - 1, dd)
  
  // 计算天数差
  let offset = Math.floor((objDate - baseDate) / 86400000)
  
  // 计算农历年
  let lunarYear = 0
  let daysOfYear = 0
  for (lunarYear = 1900; lunarYear < 2101 && offset > 0; lunarYear++) {
    daysOfYear = daysInLunarYear(lunarYear)
    offset -= daysOfYear
  }
  if (offset < 0) {
    offset += daysOfYear
    lunarYear--
  }

  // 计算农历月
  let lunarMonth = 1
  let leapMonth = leapMonthInYear(lunarYear) // 闰月
  let isLeap = false
  let daysOfMonth = 0
  
  for (lunarMonth = 1; lunarMonth < 13 && offset > 0; lunarMonth++) {
    // 处理闰月
    if (leapMonth > 0 && lunarMonth === (leapMonth + 1) && !isLeap) {
      lunarMonth--
      isLeap = true
      daysOfMonth = daysInLeapMonth(lunarYear)
    } else {
      daysOfMonth = daysInLunarMonth(lunarYear, lunarMonth)
    }
    
    offset -= daysOfMonth
    
    // 如果是闰月，且已经处理完闰月
    if (isLeap && lunarMonth === (leapMonth + 1)) {
      isLeap = false
    }
  }
  
  if (offset === 0 && leapMonth > 0 && lunarMonth === (leapMonth + 1)) {
    if (isLeap) {
      isLeap = false
    } else {
      isLeap = true
      lunarMonth--
    }
  }
  
  if (offset < 0) {
    offset += daysOfMonth
    lunarMonth--
  }
  
  // 农历日 (offset+1 是因为农历从1开始)
  const lunarDay = offset + 1
  
  // 天干地支年
  const ganIndex = (lunarYear - 4) % 10
  const zhiIndex = (lunarYear - 4) % 12
  const ganZhiYear = Gan[ganIndex] + Zhi[zhiIndex]
  
  // 生肖
  const animal = Animals[(lunarYear - 4) % 12]
  
  // 月份处理
  let lunarMonthName = lunarMonths[lunarMonth - 1] + '月'
  if (isLeap) {
    lunarMonthName = '闰' + lunarMonthName
  }
  
  return {
    lunarYear: lunarYear,
    lunarMonth: lunarMonth,
    lunarDay: lunarDay,
    isLeap: isLeap,
    lunarYearCn: ganZhiYear + '年',
    lunarMonthCn: lunarMonthName,
    lunarDayCn: lunarDays[lunarDay - 1],
    zodiac: animal,
    // 简写
    lunar: lunarDays[lunarDay - 1]
  }
}

/**
 * 获取农历年份的总天数
 * @param {number} year 农历年份
 * @returns {number} 天数
 */
function daysInLunarYear(year) {
  let sum = 348 // 29天 * 12个月
  for (let i = 0x8000; i > 0x8; i >>= 1) {
    sum += (lunarInfo[year - 1900] & i) ? 1 : 0
  }
  return sum + daysInLeapMonth(year)
}

/**
 * 获取农历闰月的天数
 * @param {number} year 农历年份
 * @returns {number} 天数
 */
function daysInLeapMonth(year) {
  if (leapMonthInYear(year)) {
    return (lunarInfo[year - 1900] & 0x10000) ? 30 : 29
  }
  return 0
}

/**
 * 获取农历某月的天数
 * @param {number} year 农历年份
 * @param {number} month 农历月份 (1-12)
 * @returns {number} 天数
 */
function daysInLunarMonth(year, month) {
  return (lunarInfo[year - 1900] & (0x10000 >> month)) ? 30 : 29
}

/**
 * 获取农历年份的闰月月份
 * @param {number} year 农历年份
 * @returns {number} 闰月月份 (0表示无闰月)
 */
function leapMonthInYear(year) {
  return lunarInfo[year - 1900] & 0xf
}

/**
 * 获取农历完整日期字符串
 * @param {number} yy 阳历年份
 * @param {number} mm 阳历月份 (1-12)
 * @param {number} dd 阳历日
 * @returns {string} 农历日期字符串
 */
function getLunarFullName(yy, mm, dd) {
  const lunar = solarToLunar(yy, mm, dd)
  return `${lunar.lunarYearCn} ${lunar.lunarMonthCn}${lunar.lunarDayCn}`
}

module.exports = {
  solarToLunar,
  getLunarFullName,
  lunarDays,
  lunarMonths,
  Gan,
  Zhi,
  Animals
}